/** \file
 * @brief  Generic template for porting guidelines
 * @page template_port Replace this with a description of this port
 * \section template_port_section  Replace this with a description of
 * this port
 * 
 * <H2> Configuration Options: Document your configuration options
 * here ########</H2>
 * <OL>
 *    <LI>  ## Config option 1.
 *    <LI>  ## Config option 2.
 * </OL>
 *
 */

/* Author: Ratish J. Punnoose, 2006
 * This file is part of TiROS, the Tickless Real-Time Operating System.
 * Copyright(c) 2006, 2007: Ratish J. Punnoose.
 * Copyright(c) 2006 Sandia Corporation. Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
 * certain rights in this software. 
 * 
 * TiROS is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 or (at your option) any later version.
 *
 * TiROS is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with TiROS; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * As a special exception, if other files instantiate templates or use macros
 * or inline functions from this file, or you compile this file and link it
 * with other works to produce a work based on this file, this file does not
 * by itself cause the resulting work to be covered by the GNU General Public
 * License. However the source code for this file must still be made available
 * in accordance with section (3) of the GNU General Public License.
 *
 * This exception does not invalidate any other reasons why a work based on
 * this file might be covered by the GNU General Public License.
 *
 */



/* Change this define to reflect your port name */
#ifndef __TEMPLATE_TIROS_PORT_H
#define __TEMPLATE_TIROS_PORT_H


/**
 * @page porting_guide Porting Guide
 * This section describes the porting of TiROS to a new platform.
 * The hardware specific port includes several files located in ROOT/src/tiros/port/port_xxx
 * A tr_port.h is required. There may be an associated tr_port.c and other assembly files if needed.
 * There will also be a file called porttime.h which contains the
 * time addition, subtraction specific to your port.
 * The tr_port.h file has several sections.
 * <OL>
 *  <LI> In a comment section at the top of the file, describe the
 *  port and the configuration options specific to the port.
 *  <LI> Include the user's configuration file proj_config.h.
 *  <LI> \ref port_config.
 *  <LI> \ref port_crit_secs.
 *  <LI> \ref port_ctxt_funcs.
 *  <LI> \ref port_time_funcs.
 *  <LI> \ref port_kernel_trap.
 *  <LI> \ref port_debug.
 * </OL> 
 * 
 */

/*@ignore@*/

/** Include the user's project configuration file */
#define TIROS_USER_CONFIG
#  include "proj_config.h"
#undef
/*@end@*/

/* Add any include files necessary */
//#include <yourincludefiles.h>
#include <stdint.h>  /* To include standard integer sizes */


/** @defgroup port_config  Define basic types and OS configuration  for your port
 * 
 * @{ */

/** Define the different integer types. or include a header file such
 * as stdint.h that
 * already has these defined. */
typedef unsigned char uint8_t;
typedef char int8_t;

typedef unsigned short uint16_t;
typedef short int16_t;

typedef unsigned long uint32_t;
typedef long int32_t;



/** Define the type field used for subunits in the time structure */
#define subtime_t uint16_t
/** Do you want the time functions inlined ? */
#define LT_INLINE static inline 



#include <tiros/tr_time.h>
/** Insert your port for time functions for your hardware */
#include "porttime.h"


/** Define the value of infinite time for this port */
#define TRPORT_INF_TIME {~0 , ~0 }


/** Will you be using register passing?  
 * This is an optimization and
 *   may be difficult on some platforms.  In that case, comment this out. */
#define TIROS_REGISTER_PASSING


/** Basic type for the hardware word.  An 8 bit system would have an
 * 8-bit integer, a 16-bit system would have a 16 bit integer, etc.
 * On a system with stdint.h, this could be uintptr_t */
typedef unsigned int osword_t;



/** Type to use for generic pointer. 
 *  Pointer types: Separate pointer types are defined for a generic
 *  pointer, stack pointer, and function pointer.  On many
 *  architectures, this may be the same.  However, there may be a need
 *  to keep this different on some hardware.  For example, on an 8051,
 *  the generic pointer may be set to refer to the IDATA memory, while
 *  the stack pointer may be set to XDATA (which takes more bytes for
 *  address storage).  Other hardware with interesting addressing such
 *  as a 20-bit address or a 23-bit address may need to keep these
 *  different types of pointers separate */
typedef void*         osptr_t;

/** Type to use for stack pointer */
typedef osword_t*    osstkptr_t;

/** Type to use for a function pointer */
typedef void (* osfnptr_t)(void *);

/** This is an integer type that can fully represent osptr_t.  If a
 * pointer takes two bytes of storage, then a 16 bit integer should be
 * used, if it takes 3 bytes of storage, then a 32 bit integer should
 * be used, etc.  If your system has a <stdint.h> file, then this
 * could be of type uintptr_t (defined in stdint.h) */
typedef unsigned int osptrword_t; 

/** Create a definition for an invalid stack pointer */ 
#define ILLEGAL_STACK ((osstkptr_t) ~0)
/** Create a definition for an illegal memory address */
#define TR_ILLEGAL_ADDR  ((osptr_t)    ~0)

/** @} */

/** @defgroup port_crit_secs Critical Sections and Interrupts
 * These functions are defined for using critical sections and dealing
 * with interrupts.
 * @{ */

/** Enable critical section calls in the the called function
 *
 *  OS_PORT_CRITICAL_ENABLE() will be called at the beginning of any
 *  function that uses  OS_CRITICAL_BEGIN or OS_CRITICAL_END.  This will be the
 *  first call after variable declaration. This is a good place to
 *  define variables that may be used by OS_BEGIN_CRITICAL and
 *  OS_CRITICAL_END
 */
#define OS_PORT_CRITICAL_ENABLE()   

/** Begin a critical section 
 * A simple way to do this would be to disable interrupts. However, it
 * would be better if the current interrupt state were stored and then
 * interrupts were disabled.  Upon ending the critical section, the
 * stored state should be restored.  The stored state can be saved in
 * a local variable, which can be defined within
 * OS_PORT_CRITICAL_ENABLE() */
#define OS_PORT_CRITICAL_BEGIN()   /* Implement this here */


/** End a critical section
 * This may be as simple as reenabling interrupts, but it is better to
 * renable the interrupt state stored in OS_PORT_BEGIN_CRITICAL() */
#define OS_PORT_CRITICAL_END()   /* Implement this here */


/** This macro will be called at the beginning of an ISR.
 * Leave this as such  */
#define OS_PORT_ISR_BEGIN()                     		\
	extern uint8_t os_isr_nesting;          		\
	os_isr_nesting++;

/** Enable interrupts
 * This allows the user to explicitly enable interrupts */
#define OS_PORT_INT_ENABLE()     /* Implement this here */

/** Disable interrupts
 * This allows the user to explicitly disable interrupts */
#define OS_PORT_INT_DISABLE()     /* Implement this here */


/* @} */


/** @defgroup port_ctxt_funcs Context Switching Functions
 * These functions should be implemented to manage a per task stack,
 * and saving and restoring context.  The context is stored so that it
 * looks like the way the stack would if all the registers were stored
 * by an interrupt function.
 *
 * @{ */

/** Define the minimum size of the context in oswords */
#define TRPORT_MIN_CTXT_SZ         64

/** Initialize a stack and create a new context for a task.
 * @param stk  Pointer to the stack.
 * @param stacksize  Size of the stack.
 * @param PC   Program counter.
 * @param init_arg   Initial argument passed to the task.
 * @return  The pointer to the task context to be used in load/save context. */
osstkptr_t /*@shared@*/ hal_stk_init(osword_t *stk, osword_t stacksize, osfnptr_t pc,
			osptr_t init_arg); 

/* If register passing is being used then define hal_retval_set */
#ifdef TIROS_REGISTER_PASSING
/** Set a return value for a task whose context is stored.
 * This is only needed if TIROS_REGISTER_PASSING is defined for your port.
 * This injects a return value into the context of a task that is currently frozen.
 * @param ctxt_ptr  Pointer to the context of the task.
 * @param retval    The return value to be injected into the task context */
static inline void hal_retval_set(/*@unused@*/osstkptr_t ctxt_ptr, 
				  /*@unused@*/ /*@null@*/ osptr_t retval)
{
}
#endif


/** Context switch from user level (non-ISR)
 *  This function is called from within an OS call, to switch the
 *  running process.  It also provides a return value. This is a
 *  pseudo return-value,  This function does not actually determine
 *  the value returned.  The return value is set by hal_retval_set
 *  which is often invoked when waking the process up from a blocked
 *  state. 
 *  This function may have to be implemented in assembly based on the
 *  port. 
 *  The function takes the following form
 * \code
 * osstkptr_t hal_ctxt_switch(void) {
 *      osstkptr_t new_ctxtptr, current_ctxtptr;
 *      current_ctxtptr = save_current_context();
 *      new_ctxtptr = osint_taskswitcher(current_ctxtptr);
 *      load_new_context(new_ctxtptr);
 * 
 *      // The code should not reach this far.  When 
 *      // new context is loaded, it will jump out of the
 *      // hal_ctxt_switch function.
 *     	return 0; 
 * }
 * \endcode   
 *
 * The function may also take the following form when there is no easy
 * access to the current stack value.
 * \code
 * osstkptr_t hal_ctxt_switch(void) {
 *      osstkptr_t ctxt_ptr, new_ctxt_ptr;
 *      ctxt_ptr = osint_running_task_ctxt();
 *      if (stkptr != ILLEGAL_STACK) {
 *            save_current_context(ctxt_ptr);
 *            new_ctxt_ptr = osint_taskswitcher(ctxt_ptr);
 *            load_new_context(new_ctxt_ptr);
 *      } else {
 *            new_ctxt_ptr = osint_taskswitcher(ctxt_ptr);
 *            load_new_context(new_ctxt_ptr);
 *      }
 *      // The code should not reach this far.  When 
 *      // new context is loaded, it will jump out of the
 *      // hal_ctxt_switch function.
 *     	return 0; 
 * }
 * \endcode   
 *
 * @return  Return value.  */
osstkptr_t /*@shared@*/ hal_ctxt_switch(void);


/** Load the given context
 * @param ctxt_ptr   Pointer to task context  */
void hal_ctxt_load(osstkptr_t ctxt_ptr);

/** Initialize the hardware.
 * Any hardware specific initialization can be performed her.
 *  Timer and kernel trap initialization 
 * can also be performed within this function. */
void hal_init(void);



 /* Bypass SPLINT verification */

/** @} End context switching functions  */	


/** @defgroup port_time_funcs  Port specific time functions
 * @{ */

/** Get the current time.
 * @param[out] lt Pointer to time structure */
void hal_time_get(/*@out@*/ trtime_t * lt);

/** Set the current time.
 * This may not always be possible, depending on the port.
 * @param[in] lt Pointer to time structure.  
 * @return 1 if successful, 0 if not possible. */
int hal_time_set( const trtime_t * lt);


/** Set an alarm for the specified time.
 *  When the alarm is reached, osint_alarm_reached is called
 * @param[in] lt Pointer to time structure. If lt is set to zero, then
 * disable alarms. */
void  hal_alarm_set(/*@null@*/ const trtime_t *lt);




#ifndef TRPORT_RESPONSE_TIME

/**  OS response time.
 * The OS wakes a task at the absolute time specified.  There might
 * however be some little overhead involved in waking it up that might 
 * delay the wakeup.  So a task that wants to wake up for a very short
 * duration of time might actually get delayed because it takes some
 * time for the OS to put it to sleep and wake it up. To avoid this,
 * TiROS takes the response overhead into account when scheduling */
#define TRPORT_RESPONSE_TIME  { 0, 80 }
#endif

/** @} End time related functions */


/** @defgroup port_kernel_trap Setup for the kernel trap
 * The kernel trap is used to reduce interrupt latency.  When an
 * interrupt occurs, the task context is not saved.  At the end of the
 * ISR,  there is a check made to see if a new task has been enabled
 * by the processing within the interrupt.  
 * 
 * In most cases, there is no
 * change and processing returns to the task that was interrupted.  If
 * this is the case, there is no overhead for saving and restoring all
 * the task context.
 *
 * In cases where a different task must run, a software interrupt is
 * raised at the end of the ISR.  When the ISR returns, the kernel
 * trap ISR is invoked due to the software interrupt.  This can save
 * the context for the current task and restore the context for the
 * new task.
 *
 *
 * @{ */

#ifndef TIROS_KERNEL_TRAP_ENABLED

/** Is a kernel trap possible on this architecture?  
 * If not, set TIROS_KERNEL_TRAP_ENABLED to 0 */
#define TIROS_KERNEL_TRAP_ENABLED  1
#endif


/** Implement the code to Invoke a kernel trap (i.e., create a
 * software interrupt).  OS_KERNEL_TRAP() is called
 * from within an ISR. On hardware where kernel trap is not
 * possible, this function may set a flag which determines if the
 * scheduler has to be invoked at the end of the ISR.   */
void OS_KERNEL_TRAP(void);
/** @} End kernel trap */


/** @defgroup port_debug Debug Functions
 *
 * These group of functions enhance the debugging capability of TiROS.
 * @{ */



#ifdef TIROSINT_DATA_DEBUG
/** Compute the program counter, from the stored context 
 * This function is used for debugging.  Implement this by extracting
 * the program counter out of the context (or stack pointer) if possible.
 *
 * @param ctxt_ptr  The pointer to the task context 
 * @return The program counter */
osptr_t hal_pc_from_ctxt(osstkptr_t ctxt_ptr);


#ifdef TIROS_STK_CHECK
/** Return the maximum stack occupancy of the task.
 * This hal implemented function should provide the 
 * maximum stack occupancy of the task whose context is given.
 * This is used for debugging.  It is valid for this function to
 * return 0, if this information is not readily extractable.
 * @param ctxt_ptr        Context of the task.
 * @param base_stkptr   The initialization stack value for this task
 *                       that was passed to hal_stk_init
 * @param stksize        The initial stack size for this task that was 
 *                       passed to hal_stk_init
 * @return The maximum stack occupancy */
osword_t hal_stkusage_max(osstpktr_t ctxt_ptr, osstkptr_t base_stkptr,
			  osword_t stksize);

/** Return the current stack occupancy of the task.
 * This hal implemented function should provide the 
 * current stack occupancy of the task whose context is given.
 * This is used for debugging.  It is valid for this function to
 * return 0, if this information is not readily extractable.
 * @param ctxt_ptr   Context of the task.
 * @param base_stkptr   The initialization stack value for this task
 *                       that was passed to hal_stk_init
 * @param stksize        The initial stack size for this task that was 
 *                       passed to hal_stk_init
 * @return The current stack occupancy */
osword_t hal_stkusage_curr(osstpktr_t ctxt_ptr, osstkptr_t base_stkptr,
			   osword_t stksize);
#endif /*TIROS_STK_CHECK */



#endif /*TIROSINT_DATA_DEBUG */

/** @} End group port_debug  */





#endif   /* End of tr_port.h */
